package com.oss.service.system;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.oss.common.BaseResponse;
import com.oss.dto.user.*;
import com.oss.entity.oss.Student;
import com.oss.entity.system.*;
import com.oss.enums.IsDeletedEnum;
import com.oss.enums.UserStatusEnum;
import com.oss.mapper.system.*;
import com.oss.service.oss.StudentService;
import com.oss.util.*;
import com.oss.util.easyexcel.EasyExcelExportByTemplateUtil;
import com.oss.vo.user.ExportUserVO;
import com.oss.vo.user.TokenVO;
import com.oss.vo.user.UserLoginReturnVO;
import com.oss.vo.user.UserVO;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author chengqiang
 */
@Slf4j
@Service
public class UserService extends ServiceImpl<UserMapper, User> {
    @Value("${outResource}")
    String outResource;
    @Autowired
    TokenService tokenService;
    @Autowired
    UserMapper userMapper;
    @Autowired
    UserRoleMapper userRoleMapper;
    @Autowired
    RoleRightsMapper roleRightsMapper;
    @Autowired
    RightsMapper rightsMapper;
    @Autowired
    TokenMapper tokenMapper;
    @Autowired
    RoleService roleService;
    @Autowired
    HttpServletRequest request;
    @Autowired
    HttpServletResponse response;
    @Autowired
    TokenUtil tokenUtil;
    @Autowired
    TemplatePathUtil templatePathUtil;
    @Autowired
    StudentService studentService;

    public BaseResponse login(LoginDto dto) {
        // 根据用户名和密码查询用户信息
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(User::getIsDeleted,IsDeletedEnum.NO.getFlag());
        queryWrapper.eq(User::getUserAccount,dto.getUserAccount());
        queryWrapper.eq(User::getUserPwd,dto.getUserPwd());
        User entity = this.baseMapper.selectOne(queryWrapper);
        if (entity == null) {
            BaseResponse.usernameOrPwdError(response,"用户名或密码错误");
            return null;
        }
        //使用userid生成token
        String userId = entity.getUserId();
        String token = "OSS_"+UUID.randomUUID().toString().replaceAll("-","");
        //认证信息存入数据库
        tokenService.insertToken(userId,token);
        UserLoginReturnVO returnVO = new UserLoginReturnVO();
        BeanUtils.copyProperties(entity,returnVO);
        returnVO.setToken(token);
        // 获取用户所有的角色对应的权限
        returnVO.setRights(getUserRightsByUserId(userId));
        returnVO.setUserPwd(userMapper.selectById(returnVO.getUserId()).getUserPwd());
        returnVO.setRoleNameList(getUserRoleList(userId));
        returnVO.setLoginIP(IPUtils.getIpAdrress(request));
        Student student = studentService.getByUserAccount(entity.getUserAccount());
        if (student != null) {
            returnVO.setStudentAccount(student.getAccount());
            returnVO.setStudentID(student.getId());
        }
        return BaseResponse.success(returnVO);
    }

    /**
     * 获取用户所有的角色的权限
     * @return 返回list
     */
    public List<Rights> getUserRightsByUserId(String userId){
        // 获取用户角色关联表
        LambdaQueryWrapper<UserRole> userRoleLambdaQueryWrapper = new LambdaQueryWrapper<>();
        userRoleLambdaQueryWrapper.eq(UserRole::getUserId,userId);
        userRoleLambdaQueryWrapper.eq(UserRole::getIsDeleted, IsDeletedEnum.NO.getFlag());
        List<UserRole> userRoleList = userRoleMapper.selectList(userRoleLambdaQueryWrapper);
        Set<String> roleIdSet = userRoleList.stream().map(UserRole::getRoleId).collect(Collectors.toSet());
        if (roleIdSet.isEmpty()) {
            return null;
        }
        // 获取角色和权限的关联表信息
        LambdaQueryWrapper<RoleRights> roleRightsLambdaQueryWrapper = new LambdaQueryWrapper<>();
        roleRightsLambdaQueryWrapper.eq(RoleRights::getIsDeleted,IsDeletedEnum.NO.getFlag());
        roleRightsLambdaQueryWrapper.in(RoleRights::getRoleId,roleIdSet);
        List<RoleRights> roleRightsList = roleRightsMapper.selectList(roleRightsLambdaQueryWrapper);
        Set<String> rightsIdSet = roleRightsList.stream().map(RoleRights::getRightsId).collect(Collectors.toSet());
        if (rightsIdSet.isEmpty()) {
            return null;
        }
        // 获取所有权限
        LambdaQueryWrapper<Rights> rightsLambdaQueryWrapper = new LambdaQueryWrapper<>();
        rightsLambdaQueryWrapper.eq(Rights::getIsDeleted,IsDeletedEnum.NO.getFlag());
        rightsLambdaQueryWrapper.in(Rights::getRightsId,rightsIdSet);
        List<Rights> list = rightsMapper.selectList(rightsLambdaQueryWrapper);
        return list;
    }



    public IPage<UserVO> selectByPage(UserPageDto dto) {
        LambdaQueryWrapper<User> pageLambdaQueryWrapper = new LambdaQueryWrapper<>();
        pageLambdaQueryWrapper.eq(User::getIsDeleted, IsDeletedEnum.NO.getFlag());
        pageLambdaQueryWrapper.eq(StringUtils.isNotBlank(dto.getUserAccount()), User::getUserAccount,dto.getUserAccount());
        pageLambdaQueryWrapper.eq(dto.getUserStatus() != null, User::getUserStatus,dto.getUserStatus());
        pageLambdaQueryWrapper.like(StringUtils.isNotBlank(dto.getUserName()), User::getUserName,dto.getUserName());
        pageLambdaQueryWrapper.orderByDesc(User::getCreateTime);
        IPage<User> ipage = this.page(new Page(dto.getPageNo(),dto.getPageSize()),pageLambdaQueryWrapper);
        Map<String, List<String>> userRoleMap = new HashMap<>();
        if (CollectionUtils.isNotEmpty(ipage.getRecords())){
            Set<String> userIdSet = ipage.getRecords().stream().map(User::getUserId).collect(Collectors.toSet());
            userRoleMap = roleService.selectRightsByUserId(userIdSet);
        }
        Map<String, List<String>> finalUserRoleMap = userRoleMap;
        return ipage.convert(entity->{
            UserVO vo = new UserVO();
            BeanUtils.copyProperties(entity,vo);
            vo.setUserStatusName(UserStatusEnum.getStatusEnumsDescByKey(vo.getUserStatus()));
            List<String> roleNameList = finalUserRoleMap.get(entity.getUserId());
            vo.setRoleNameList(roleNameList);
            return vo;
        });
    }

    public BaseResponse addUser(UserAddDto dto) {
        LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(User::getIsDeleted,IsDeletedEnum.NO.getFlag());
        lambdaQueryWrapper.eq(User::getUserAccount,dto.getUserAccount());
        long count = userMapper.selectCount(lambdaQueryWrapper);
        if(count > 0){
            return BaseResponse.error("账户已存在");
        }
        User entity = new User();
        BeanUtils.copyProperties(dto,entity);
        entity.setUserStatus(1);
        entity.setUserId(SnowFlakeUtil.getID());
        // 默认头像
        entity.setAvatarPath("defaultUserAvator.jpg");
        userMapper.insert(entity);
        // 循环插入用户和角色关联信息
        for (String roleId : dto.getRoleIds()) {
            UserRole userRoleEntity = new UserRole();
            userRoleEntity.setUserId(entity.getUserId());
            userRoleEntity.setRoleId(roleId);
            userRoleMapper.insert(userRoleEntity);
        }
        return BaseResponse.success("操作成功");
    }

    public BaseResponse updateUser(UserUpdateDto dto) {
        LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(User::getIsDeleted,IsDeletedEnum.NO.getFlag());
        lambdaQueryWrapper.eq(User::getUserAccount,dto.getUserAccount());
        lambdaQueryWrapper.ne(User::getUserId,dto.getUserId());
        long count = userMapper.selectCount(lambdaQueryWrapper);
        if(count > 0){
            return BaseResponse.error("账户已存在");
        }
        // 1. 先修改用户基本信息
        LambdaUpdateWrapper<User> lambdaUpdateWrapper = new LambdaUpdateWrapper<>();
        lambdaUpdateWrapper.eq(User::getUserId,dto.getUserId());
        User entity = new User();
        BeanUtils.copyProperties(dto,entity);
        userMapper.update(entity,lambdaUpdateWrapper);
        // 2. 删除用户和角色关联表中信息未删除的关联信息
        LambdaUpdateWrapper<UserRole> userRoleLambdaUpdateWrapper = new LambdaUpdateWrapper<>();
        userRoleLambdaUpdateWrapper.set(UserRole::getIsDeleted,IsDeletedEnum.YES.getFlag());
        userRoleLambdaUpdateWrapper.eq(UserRole::getIsDeleted,IsDeletedEnum.NO.getFlag());
        userRoleLambdaUpdateWrapper.eq(UserRole::getUserId,dto.getUserId());
        userRoleMapper.update(null,userRoleLambdaUpdateWrapper);
        // 3. 循环插入用户和角色关联信息
        for (String roleId : dto.getRoleIdList()) {
            UserRole userRoleEntity = new UserRole();
            userRoleEntity.setUserId(dto.getUserId());
            userRoleEntity.setRoleId(roleId);
            userRoleMapper.insert(userRoleEntity);
        }
        return  BaseResponse.success("操作成功");
    }

    public String updateUserPwd(UserUpdatePwdDto dto) {
        LambdaUpdateWrapper<User> lambdaUpdateWrapper = new LambdaUpdateWrapper<>();
        lambdaUpdateWrapper.eq(User::getUserId,dto.getUserId());
        lambdaUpdateWrapper.set(User::getUserPwd,dto.getUserPwd());
        userMapper.update(null,lambdaUpdateWrapper);
        return "操作成功";
    }

    public String resetUserPwd(UserResetPwdDto dto) {
        LambdaUpdateWrapper<User> lambdaUpdateWrapper = new LambdaUpdateWrapper<>();
        lambdaUpdateWrapper.eq(User::getUserId,dto.getUserId());
        lambdaUpdateWrapper.set(User::getUserPwd,"Dzrh@123456");
        userMapper.update(null,lambdaUpdateWrapper);
        return "操作成功";
    }

    public String deleteUser(UserDeleteDto dto) {
        LambdaUpdateWrapper<User> lambdaUpdateWrapper = new LambdaUpdateWrapper<>();
        lambdaUpdateWrapper.eq(User::getUserId,dto.getUserId());
        lambdaUpdateWrapper.set(User::getIsDeleted,IsDeletedEnum.YES.getFlag());
        userMapper.update(null,lambdaUpdateWrapper);
        return "操作成功";
    }

    public UserLoginReturnVO getUserByToken(String token) {
        try {
            Claims claims = tokenUtil.validateToken(token);
            // 取出用户id，透传给下游微服务
            String userId = claims.getSubject();
        } catch (ExpiredJwtException e) {
            new RuntimeException("Token已过期");
        } catch (Exception e) {
            new RuntimeException("非法Token");
        }
        LambdaQueryWrapper<Token> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(Token::getToken,token);
        Token tokenEntity = tokenService.getOne(lambdaQueryWrapper);
        if (token != null){
            String userId = tokenEntity.getUserId();
            User entity = userMapper.selectById(userId);
            UserLoginReturnVO returnVO = new UserLoginReturnVO();
            BeanUtils.copyProperties(entity,returnVO);
            returnVO.setRights(getUserRightsByUserId(userId));
            returnVO.setRoleNameList(getUserRoleList(userId));
            returnVO.setLoginIP(IPUtils.getIpAdrress(request));
            Student student = studentService.getByUserAccount(entity.getUserAccount());
            if (student != null) {
                returnVO.setStudentAccount(student.getAccount());
                returnVO.setStudentID(student.getId());
            }
            return returnVO;
        } else {
            return  null;
        }
    }

    public String logout(String token) {
        LambdaUpdateWrapper<Token> lambdaUpdateWrapper = new LambdaUpdateWrapper<>();
        lambdaUpdateWrapper.eq(Token::getToken,token);
        lambdaUpdateWrapper.set(Token::getExpirationTime, LocalDateTime.now());
        tokenMapper.update(null,lambdaUpdateWrapper);
        return "操作成功";
    }

    /**
     * 按用户ID获取用户
     * @param ids 用户ID集合
     * @return 返回map key=用户ID, value=用户名称
     */
    public Map<String,String> selectByIds(Set<String> ids) {
        return userMapper.selectBatchIds(ids).stream().collect(Collectors.toMap(User::getUserId, item->{
            if ("1".equals(item.getUserId())) {
                return "系统";
            } else if ("-1".equals(item.getUserId())) {
                return "外部导入";
            } else {
                return item.getUserName();
            }
        },(v1, v2)->v2));
    }

    public UserVO getUserById(String userId) {
        UserVO vo = new UserVO();
        User entity = userMapper.selectById(userId);
        LambdaQueryWrapper<UserRole> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(UserRole::getUserId,userId);
        lambdaQueryWrapper.eq(UserRole::getIsDeleted,IsDeletedEnum.NO.getFlag());
        List<String>  roleIds = userRoleMapper.selectList(lambdaQueryWrapper).stream().map(UserRole::getRoleId).collect(Collectors.toList());
        BeanUtils.copyProperties(entity,vo);
        vo.setRoleIdList(roleIds);
        return vo;
    }

    public List<User> listAll() {
        LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(User::getIsDeleted,IsDeletedEnum.NO.getFlag());
        return userMapper.selectList(lambdaQueryWrapper);
    }

    public String uploadAvatar(MultipartFile file) throws Exception {
        // 源文件名称
        String oldName = file.getOriginalFilename();
        // 文件后缀
        oldName = oldName.substring(oldName.lastIndexOf("."));
        String savePath = getSavePath()+"userAvatar/";
        File saveFileDir = new File(savePath);
        if (!saveFileDir.exists()){
            saveFileDir.mkdirs();
        }
        // 文件名称
        String fileName = System.currentTimeMillis()+oldName;
        File saveFile = new File(savePath+fileName);
        // 保存文件到指定目录
        file.transferTo(saveFile);
        return fileName;
    }
    /**
     * 获取上传文件存储的目录
     * @return 返回路径
     */
    public String getSavePath(){
        String path = outResource;
        File file = new File(path);
        // 目录不存在就创建
        if (!file.exists()) {
            file.mkdirs();
        }
        return path;
    }

    public String updateAvatar(UserAvatarUploadDto dto) {
        User entity = new User();
        BeanUtils.copyProperties(dto,entity);
        userMapper.updateById(entity);
        return "操作成功";
    }
    private List<String> getUserRoleList(String userId) {
        LambdaQueryWrapper<UserRole> userRoleLambdaQueryWrapper = new LambdaQueryWrapper<>();
        userRoleLambdaQueryWrapper.eq(UserRole::getUserId,userId);
        userRoleLambdaQueryWrapper.eq(UserRole::getIsDeleted,IsDeletedEnum.NO.getFlag());
        List<UserRole> userRoleList = userRoleMapper.selectList(userRoleLambdaQueryWrapper);
        Set<String> roleIdSet = userRoleList.stream().map(UserRole::getRoleId).collect(Collectors.toSet());
        if (roleIdSet.isEmpty()) {
            return null;
        } else{
            LambdaQueryWrapper<Role> roleLambdaQueryWrapper = new LambdaQueryWrapper<>();
            roleLambdaQueryWrapper.eq(Role::getIsDeleted,IsDeletedEnum.NO.getFlag());
            roleLambdaQueryWrapper.in(Role::getRoleId,roleIdSet);
            return roleService.list(roleLambdaQueryWrapper).stream().map(Role::getRoleName).distinct().collect(Collectors.toList());
        }
    }

    public IPage<TokenVO> loginRecordsPage(TokenPageDto dto) {
        LambdaQueryWrapper<Token> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(Token::getIsDeleted,IsDeletedEnum.NO.getFlag());
        lambdaQueryWrapper.eq(StringUtils.isNotBlank(dto.getUserId()), Token::getUserId,dto.getUserId());
        if (dto.getLoginDate() != null) {
            lambdaQueryWrapper.ge(Token::getCreateTime,dto.getLoginDate().atStartOfDay());
        }
        if (dto.getLoginDateEnd() != null) {
            lambdaQueryWrapper.le(Token::getCreateTime,LocalDateTime.of(dto.getLoginDateEnd(), LocalTime.MAX));
        }
        lambdaQueryWrapper.orderByDesc(Token::getCreateTime);
        IPage<Token> ipage = tokenMapper.selectPage(new Page<>(dto.getPageNo(),dto.getPageSize()),lambdaQueryWrapper);
        Set<String> ids = new HashSet<>();
        if (CollectionUtils.isNotEmpty(ipage.getRecords())) {
            ids = ipage.getRecords().stream().map(Token::getUserId).collect(Collectors.toSet());
        }
        Map<String, User> userMap;
        if (!ids.isEmpty()) {
            userMap = userMapper.selectBatchIds(ids).stream().collect(Collectors.toMap(User::getUserId, item->item,(v1, v2)->v2));
        } else {
            userMap = new HashMap<>();
        }
        return ipage.convert(entity->{
            TokenVO vo = new TokenVO();
            BeanUtils.copyProperties(entity,vo);
            if (userMap.containsKey(entity.getUserId())) {
                User user = userMap.get(entity.getUserId());
                vo.setCreatorName(user.getUserName());
                vo.setUserAccount(user.getUserAccount());
                vo.setLoginIP(entity.getIp());
            }
            return vo;
        });
    }

    public void exportUser() {
        LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(User::getIsDeleted,IsDeletedEnum.NO.getFlag());
        List<User> list = this.list(lambdaQueryWrapper);
        List<ExportUserVO> voList = list.stream().map(entity->{
            ExportUserVO vo = new ExportUserVO();
            BeanUtils.copyProperties(entity,vo);
            return vo;
        }).collect(Collectors.toList());
        String outPath = "C:\\Users\\dzrh\\Desktop\\userExportData.xlsx";
        String templatePath = templatePathUtil.getUserExportTemplatePath();
        EasyExcelExportByTemplateUtil.exportExcelByTemplate(outPath,templatePath,voList);
    }
    /**
     * 根据账户获取用户信息(学员专用)
     * @param phone 手机号即为账户
     * @return
     */
    public User getByAccount(String phone) {
        LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(User::getIsDeleted,IsDeletedEnum.NO.getFlag());
        lambdaQueryWrapper.eq(User::getUserAccount,phone);
        return this.getOne(lambdaQueryWrapper);
    }

    /**
     * 根据账户统计用户数量(学员专用)
     * @param phone 手机号即为账户
     * @return
     */
    public long countByAccount(String phone) {
        LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(User::getIsDeleted,IsDeletedEnum.NO.getFlag());
        lambdaQueryWrapper.eq(User::getUserAccount,phone);
        return this.count(lambdaQueryWrapper);
    }
}
